package com.huayun.plugin.pointcloud.service;

import com.huayun.plugin.pointcloud.domain.Point;
import com.huayun.plugin.pointcloud.fileparser.PointCloudFileParser;
import com.huayun.plugin.pointcloud.repos.PointCloudRepository;
import com.huayun.plugin.pointcloud.util.UtilPointCloud;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

@Service
public class PointCloudService {
    private final Logger log = LoggerFactory.getLogger(PointCloudService.class);
    private final PointCloudRepository pointCloudRepository;

    public PointCloudService(PointCloudRepository pointCloudRepository) {
        this.pointCloudRepository = pointCloudRepository;
    }

    /*
     * 根据pcd文件解析并调用算法生成网格文件
     *
     * @param userName 用户名
     * @param file 文件
     * @param os 返回输出的目标文件流
     * */
    public void createMeshGridFile(String userName, double searchRadius, boolean isAutoSearchRadius, MultipartFile file, OutputStream os) throws IOException {
        log.info("user.dir Path: " + System.getProperty("user.dir"));
        String tempUserName = userName;
        String folderPath = System.getProperty("user.dir") + "\\TempFile\\";

        Path path = Paths.get(folderPath);
        if (!Files.exists(path)) {
            Files.createDirectories(path);
        }

        String objectSrcFileId = ObjectId.get().toString();
        String fileSrcName = file.getOriginalFilename();
        String fileSuffix = fileSrcName.replaceAll(file.getName(),"");
        String fileName = objectSrcFileId +fileSuffix;
        File localFile = new File(folderPath, fileName);
        file.transferTo(localFile);

        // 读取文件计计算自动搜索的半径
        if(isAutoSearchRadius){
            searchRadius = this.getAutoSearchRadius(file.getOriginalFilename(),localFile);
            searchRadius = 1.5 * searchRadius; //在平均值的基础上加大一些
        }

        // 点云转网格文件处理
        String sourceFile = folderPath + fileName;
        String objectId = ObjectId.get().toString();
        String tempVtkFile = folderPath + objectId + ".vtk";
        String destObjFile = folderPath + objectId + ".obj";

/*        double multiplier = 1.5;
        if(searchRadius < 1){
            multiplier = 2.5;
        }*/
        double multiplier = 2.5;
        log.info("CreateMeshGridFile: " + userName + ",searchRadius=" + searchRadius + ",multiplier=" + multiplier);

        int toolResult = UtilPointCloud.pclToolDll.PointCloudToMesh(sourceFile, tempVtkFile, destObjFile, searchRadius, multiplier);
        if (toolResult == 0) {
            File destFile = new File(destObjFile);
            if (destFile.exists()) {
                try {
                    // java11用法
                    //FileInputStream inputStream = new FileInputStream(destFile);
                    //StreamUtils.copy(inputStream.readAllBytes(), os);
                    // java8用法
                    StreamUtils.copy(Files.readAllBytes(Paths.get(destFile.toURI())), os);
                } catch (IOException exception) {
                    throw new IOException(exception);
                }
            } else {
                log.error("PCL点云转换出现错误，目标文件未创建成功！");
            }
        } else {
            String errorMeg; //0：正常/-1：pcd文件无点数据/-2：txt点云读取出现错误/-3：点数量为0/-4：网格三角形未正常创建
            switch (toolResult) {
                case -1:
                    errorMeg = "pcd文件无点数据。";
                    break;
                case -2:
                    errorMeg = "txt点云读取出现错误。";
                    break;
                case -3:
                    errorMeg = "点数量为0。";
                    break;
                case -4:
                    errorMeg = "网格三角形未正常创建。";
                    break;
                default:
                    errorMeg = "其他未知错误。";

            }
            log.error("pclToolDll.PointCloudToMesh执行返回值为：" + toolResult + "," + errorMeg);
        }
    }

    /*
    * 根据文件自动计算出剖分搜索半径
    *
    * @param originName 文件名
    * @param file 文件
    * @return double类型计算结果
    * */
    private double getAutoSearchRadius(String originName, File file) throws IOException {
        int pointsNum = 20;
        PointCloudFileParser pointCloudFileParser = new PointCloudFileParser(originName, file);
        List<Point> points = pointCloudFileParser.ReadPCPoint();
        List usedPoint = new ArrayList();
        if (points.size() > 20) {
            usedPoint = points.subList(0, pointsNum);
        } else {
            usedPoint = points;
        }
        return this.calculateSearchRadius(usedPoint);
    }

    private double calculateSearchRadius(List<Point> points) {
        double sumLengh = 0;
        if(points.size() <= 1) {
            return 0;
        }
        int num = 0;
        for (int i = 0; i < points.size() - 1; i++) {
            sumLengh += points.get(i).getDistance(points.get(i + 1));
            num++;
        }
        return sumLengh/num;
    }
}
